package com.gmail.rusal4ica.dots;


import com.gmail.rusal4ica.logic.Board;
import com.gmail.rusal4ica.logic.DotsBot;
import com.gmail.rusal4ica.logic.DotsGame;
import com.gmail.rusal4ica.logic.Player;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.TextView;

/**
 * @author The Imperial Sword Team
 */

public class PlayActivity extends Activity {
	private DotsGame game;
	private Button[][] button = new Button[OptionsActivity.sizeN][OptionsActivity.SIZE_M];
	private TextView time;
	private TextView player;

	private final int R_TOKEN_PLAYER_ONE = R.drawable.ic_shell_1;
	private final int R_TOKEN_PLAYER_TWO = R.drawable.ic_shell_2;

	private  static long countUp = 0;
	private long startTime;
	private Chronometer stopWatch;

	private String[] tagIndexes;

	private int[][] idButtons = { 
			{ R.id.dot1, R.id.lineh1, R.id.dot2, R.id.lineh2, 
				R.id.dot3, R.id.lineh3, R.id.dot4, R.id.lineh4, R.id.dot5 },
				{ R.id.linev1, R.id.box1, R.id.linev2, R.id.box2, R.id.linev3,
					R.id.box3, R.id.linev4, R.id.box4, R.id.linev5 },
					{ R.id.dot6, R.id.lineh5, R.id.dot7, R.id.lineh6, 
						R.id.dot8, R.id.lineh7, R.id.dot9, R.id.lineh8, R.id.dot10 },		
						{ R.id.linev6, R.id.box5, R.id.linev7, R.id.box6, R.id.linev8,
							R.id.box7, R.id.linev9, R.id.box8, R.id.linev10 },	
							{ R.id.dot11, R.id.lineh9, R.id.dot12, R.id.lineh10, 
								R.id.dot13, R.id.lineh11, R.id.dot14, R.id.lineh12, R.id.dot15 },	
								{ R.id.linev11, R.id.box9, R.id.linev12, R.id.box10, R.id.linev13,
									R.id.box11, R.id.linev14, R.id.box12, R.id.linev15 },	
									{ R.id.dot16, R.id.lineh13, R.id.dot17, R.id.lineh14, 
										R.id.dot18, R.id.lineh15, R.id.dot19, R.id.lineh16, R.id.dot20 },		
										/////////////////// *** xml 3x4 *** ///////////////////			
										{ R.id.linev16, R.id.box13, R.id.linev17, R.id.box14, R.id.linev18,
											R.id.box15, R.id.linev19, R.id.box16, R.id.linev20 },		
											{ R.id.dot21, R.id.lineh17, R.id.dot22, R.id.lineh18, 
												R.id.dot23, R.id.lineh19, R.id.dot24, R.id.lineh20, R.id.dot25 },	
												/////////////////// *** xml 4x4 *** ///////////////////			
												{ R.id.linev21, R.id.box17, R.id.linev22, R.id.box18, R.id.linev23,
													R.id.box19, R.id.linev24, R.id.box20, R.id.linev25 },			
													{ R.id.dot26, R.id.lineh21, R.id.dot27, R.id.lineh22, 
														R.id.dot28, R.id.lineh23, R.id.dot29, R.id.lineh24, R.id.dot30 }			
													/////////////////// *** xml 5x4 *** ///////////////////
	};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView();

		player = (TextView)findViewById(R.id.player);

		createTiles(idButtons, OptionsActivity.sizeN);      
		setWatch();     
		initGameObject();
		player.setText("Player: " + Player.getCurrentPlayer().getName());
	}

	/**
	 * The method sets the correct xml file for the needed size of the game.
	 */
	private void setContentView(){
		switch(OptionsActivity.sizeN){
		case(7): 
			setContentView(R.layout.play3);
		break;
		case(9):
			setContentView(R.layout.play4);
		break;
		case(11):
			setContentView(R.layout.play5);
		break;
		default:
			setContentView(R.layout.play3);
		}
	}

	/**
	 * The method sets the watch and time elapsed for the game.
	 */
	private void setWatch(){
		stopWatch = (Chronometer) findViewById(R.id.chrono);
		startTime = SystemClock.elapsedRealtime();
		time = (TextView) findViewById(R.id.time);
		stopWatch.setOnChronometerTickListener(chronListener);
		stopWatch.start(); 
	}

	/**
	 * The method initializes the game object 
	 * according to the OptionsActivity.game parameter.
	 * There are two options - play against human and against the machine.
	 */
	private void initGameObject(){
		switch(OptionsActivity.game){
		case(1):
			game = new DotsGame(OptionsActivity.sizeN, OptionsActivity.SIZE_M); //dopisvane konstruktor za sizeN i sizeM
		break;
		case(2):
			game = new DotsBot(OptionsActivity.sizeN, OptionsActivity.SIZE_M); //dopisvane konstruktor za sizeN i sizeM
		break;
		}
	}

	/**
	 * The method initializes the buttons from the xml file.
	 * 
	 * @param idButtons - the array with the buttons IDs
	 * @param sizeN - the length of the array of buttons
	 */
	private void createTiles(int[][] idButtons, int sizeN){ 
		for(int i = 0; i < sizeN; i++){
			for(int j = 0; j < OptionsActivity.SIZE_M; j++){
				button[i][j] = (Button)findViewById(idButtons[i][j]);
				if(button[i][j].isEnabled()){
					button[i][j].setOnClickListener(playTurn);
				}
			}
		}
	}

	/**
	 * The method defines the behavior of the button when clicked.
	 */
	private View.OnClickListener playTurn = new View.OnClickListener() {
		String sTag;

		@Override
		public void onClick(View v) {
			sTag = (String)v.getTag();
			tagIndexes = sTag.split(",");

			int i = Integer.parseInt(tagIndexes[0]);
			int j = Integer.parseInt(tagIndexes[1]);

			game.playDotsGame(i, j);

			reflectChangesAfterPlayedMove(i, j);

			//if the game is against gsm
			if((OptionsActivity.game == 2) && (Player.getCurrentPlayer().getName().equals(DotsGame.PLAYER_TWO_NAME))){
				do {
					((DotsBot)game).makeMove();
					reflectChangesAfterPlayedMove(((DotsBot)game).getPlayedIndexN(), ((DotsBot)game).getPlayedIndexM());
				} while(Player.getCurrentPlayer().getName().equals(DotsGame.PLAYER_TWO_NAME));
			}
			if(game.isGameOver()){
				stopWatch.stop();
				player.setTextColor(Color.RED);
				player.setText(game.theWinnerIs().getName() + " won!");				
			} else {
				player.setText("Player: " + Player.getCurrentPlayer().getName());
			}
		}
	};

	/**
	 * The method makes the necessary changes after the played move
	 * needed for reflecting them on the GUI.
	 * 
	 * @param i - row index
	 * @param j - column index
	 */
	public void reflectChangesAfterPlayedMove(int i, int j) {
		placeLine(i, j);
		button[i][j].setEnabled(false);
		boolean temp = game.isLineClosingBox(game.getDotsBoard().getBoard(), i, j);
	
		if(temp){
			placeToken(i, j);
		} else {
			game.switchIfNeeded(i, j);
		}
	}

	/**
	 * The method places the line in GUI.
	 * 
	 * @param i - row index
	 * @param j - column index
	 */
	private void placeLine(int row, int col){
		if(game.getDotsBoard().getBoardCharAt(row, col) == Board.LINE_FIELD_VERTICAL){
			button[row][col].setBackgroundResource(R.drawable.ic_grid_line_v);
		} else {
			button[row][col].setBackgroundResource(R.drawable.ic_grid_line_h);
		}
	}

	/**
	 * The method places the token of the player on the closed field.
	 */
	private void placeToken(int i, int j){ 	
		if(game.getDotsBoard().getBoardCharAt(i, j) == Board.LINE_FIELD_HORIZONTAL){
			if(compareSigns(i - 1, j)){
				setDrawableRes(i - 1, j);
			}
			if(compareSigns(i + 1, j)){
				setDrawableRes(i + 1, j);
			}					
		} else {
			if(compareSigns(i, j - 1)){
				setDrawableRes(i, j - 1);
			}
			if(compareSigns(i, j + 1)){
				setDrawableRes(i, j + 1);
			}
		}
	}

	/**
	 * The method sets the drawable resource of the button for the current player.
	 * 
	 * @param i - row index
	 * @param j - column index
	 */
	public void setDrawableRes(int i, int j) {
		if(Player.getCurrentPlayer().getSign() == DotsGame.PLAYER_ONE_SIGN){
			button[i][j].setBackgroundResource(R_TOKEN_PLAYER_ONE);
		} else {
			button[i][j].setBackgroundResource(R_TOKEN_PLAYER_TWO);
		}
	}

	/**
	 * The method compares the given sign on the given coordinates
	 * to the sign of the current player.
	 * 
	 * @param i - row index
	 * @param j - column index
	 * @return - true or false
	 */
	private boolean compareSigns(int i, int j){
		if(game.getDotsBoard().isColumnIndexInRange(j) && game.getDotsBoard().isRowIndexInRange(i)){
			return game.getDotsBoard().getBoardCharAt(i, j) != Board.FIELD_EMPTY;
		}
		return false;
	}

	/**
	 * The method uses the system clock for estimating and showing the time elapsed.
	 * Implements onChronometerTick
	 * 
	 */
	private Chronometer.OnChronometerTickListener chronListener = new Chronometer.OnChronometerTickListener() {
		String msg;

		@Override
		public void onChronometerTick(Chronometer ch){
			countUp = (SystemClock.elapsedRealtime() - ch.getBase()) / 1000;
			msg = Utility.showTime(countUp);
			time.setText("Time: " + msg);
		}   		
	};
}
